home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 4 / ETO Development Tools 4.iso / Tools - Objects / MacApp / MacApp 3.0a2 / Libraries / UBusyCursor.cp < prev    next >
Text File  |  1991-05-01  |  14KB  |  435 lines

  1. // UBusyCursor.cp 
  2. // Copyright © 1985-1991 Apple Computer, Inc. All rights reserved.
  3.  
  4. #ifndef __UBUSYCURSOR__
  5. #include <UBusyCursor.h>
  6. #endif
  7.  
  8. #ifndef __UFAILURE__
  9. #include <UFailure.h>
  10. #endif
  11.  
  12. #ifndef __UMEMORY__
  13. #include <UMemory.h>
  14. #endif
  15.  
  16. #ifndef __UMACAPPUTILITIES__
  17. #include <UMacAppUtilities.h>
  18. #endif
  19.  
  20. #ifndef __TRAPS__
  21. #include <Traps.h>
  22. #endif
  23.  
  24. #ifndef __ULOMEM__
  25. #include <ULoMem.h>
  26. #endif
  27.  
  28. #ifndef __TOOLUTILS__
  29. #include <ToolUtils.h>
  30. #endif
  31.  
  32. #ifndef __RETRACE__
  33. #include <Retrace.h>
  34. #endif
  35.  
  36. #ifndef __RESOURCES__
  37. #include <Resources.h>
  38. #endif
  39.  
  40. struct QElemWithA5
  41. {
  42.     long OldA5;                                    // A place to store the old value of A5 since
  43.     // when debugging the compiler trashes the
  44.     // value of A0 for any locals in the VBL task
  45.     // thus makeing the pointer to the
  46.     // paramblockrec unavailable
  47.     long A5;                                    // The value of A5 will be stored here to be
  48.     // available at VBL time
  49.     VBLTask q;                                    // vbl queue element for changing the cursor
  50. };
  51.  
  52.  
  53. struct CursorInfo
  54. {
  55.     QElemWithA5 aQElemWithA5;                    // vbl queue elem. for changing the cursor 
  56.     Boolean inColor;                            // Is the saved cursor in color? 
  57.     Cursor origCursor;                            // Cursor at the time the busy cursor was put
  58.     // up, if not in color
  59.     CCrsrHandle origCCursor;                    // Cursor at the time the busy cursor was put
  60.     // up, if in color
  61.     short busyDelay;                            // time in 1/60 second before cursor changes
  62.     // to watch
  63.     Boolean inControl;                            // managed by MacApp; TRUE iff MacApp is in
  64.     // control(); if FALSE we don't change the
  65.     // cursor at all
  66.     Boolean changeToBusy;                        // if TRUE, we automagically switch to the
  67.     // busy cursor in the VBL task and switch to
  68.     // origCursor on a call to GetNextEvent or
  69.     // EventAvail(); applications can changed this
  70.     //  as necessary
  71.     Boolean busyOn;                                // TRUE if the busy cursor on 
  72.     Cursor currentCursor;                        // the current display cursor 
  73.     AcurRsrcHandle cursorState;                    // the ‘acur’ resource
  74.     short animateDelay;                            // ticks before we spin the cursor 
  75.     long timeoutCount;                            // spins before animation times out 
  76.     long spinCount;                                // spins since last BusyAnimate call 
  77. };
  78.  
  79.  
  80. typedef CursorInfo* CursorInfoPointer;
  81. typedef CursorInfoPointer* CursorInfoHandle;
  82.  
  83. //--------------------------------------------------------------------------------------------------
  84. const short kAcurRsrcID = 256;
  85.  
  86. //--------------------------------------------------------------------------------------------------
  87. CursorInfo pCursorInfo;
  88. TrapPatch pEAPatch;                                // patch for EventAvail 
  89. TrapPatch pGNEPatch;                            // patch for GetNextEvent 
  90. TrapPatch pICPatch;                                // patch for InitCursor 
  91. TrapPatch pSCCPatch;                            // patch for SetCCursor 
  92. TrapPatch pSCPatch;                                // patch for SetCursor 
  93. TrapPatch pSDPatch;                                // patch for StillDown under A/UX 
  94. TrapPatch pWMUPatch;                            // patch for WaitMouseUp under A/UX 
  95.  
  96. //--------------------------------------------------------------------------------------------------
  97. TBusyCursor* gBusyCursor;
  98.  
  99. //--------------------------------------------------------------------------------------------------
  100. // #if qTrace
  101. #pragma segment MABusyCursorRes
  102.  
  103. pascal void ResetBusyCursor(void)
  104. {
  105.     long OldA5;
  106.  
  107.     OldA5 = SetCurrentA5();                        // ***** Called from trap patches *****
  108.     gBusyCursor->Reset(pCursorInfo.busyDelay);
  109.     SetA5(OldA5);
  110. }
  111.  
  112. //--------------------------------------------------------------------------------------------------
  113. // if qTrace
  114. #pragma segment MABusyCursorRes
  115. // must be in Main segment, and cannot call
  116. // to any other segment because SetCursor is
  117. // called from the ABusyTask VBL task
  118.  
  119. // The SetCCursor patch, used to remember the color cursor being set.
  120. // Installed as a "Head" patch, meaning the original SetCCursor trap
  121. // is called after this code has completed.
  122.  
  123. pascal void SetCMacAppCursor(CCrsrHandle theCCursor)
  124. {
  125.     long OldA5;
  126.  
  127.     OldA5 = SetCurrentA5();                        // ***** Called from trap patches *****
  128.     gBusyCursor->TurnOff();
  129.     pCursorInfo.inColor = TRUE;
  130.     pCursorInfo.origCCursor = theCCursor;        // Save a copy of the color cursor 
  131.     SetA5(OldA5);
  132. }
  133.  
  134. //--------------------------------------------------------------------------------------------------
  135. #pragma segment MAInit
  136.  
  137. pascal void InitUBusyCursor(void)
  138. {
  139.     gBusyCursor = NULL;                            // ??? should we still have initubusycursor? 
  140.     gBusyCursor = new TBusyCursor;                // Create the BusyCursor mechanism 
  141.     gBusyCursor->IBusyCursor();                    // Automatically sets gBusyCursor 
  142. }
  143.  
  144. //--------------------------------------------------------------------------------------------------
  145. // if qTrace
  146. #pragma segment MABusyCursorRes
  147. // must be in Main segment, and cannot call
  148. // to any other segment because SetCursor is
  149. // called from the ABusyTask VBL task
  150.  
  151. // Patches SetCursor to remember the cursor being set. Installed as a
  152. // "Head" patch, meaning the original SetCursor trap is called after
  153. // this code has completed. Also called from InitMacAppCursor.
  154.  
  155. pascal void SetMacAppCursor(Cursor& theCursor)
  156. {
  157.     long OldA5;
  158.  
  159.     OldA5 = SetCurrentA5();                        // ***** Called from trap patches *****
  160.     gBusyCursor->TurnOff();
  161.     // If we are setting the cursor to the busy cursor, then don't save it 
  162.     if (&theCursor != &pCursorInfo.currentCursor)
  163.     {
  164.         pCursorInfo.inColor = FALSE;
  165.         pCursorInfo.origCursor = theCursor;
  166.     }
  167.     else
  168.         pCursorInfo.busyOn = TRUE;                // because BusyTurnOff set it to FALSE 
  169.     SetA5(OldA5);
  170. }
  171.  
  172. //--------------------------------------------------------------------------------------------------
  173. // if qTrace
  174. #pragma segment MABusyCursorRes
  175.  
  176. // Called when the InitCursor trap is executed.  After completion, we jump
  177. // to the ROM InitCursor.
  178.  
  179. pascal void InitMacAppCursor(void)
  180. {
  181.     long OldA5;
  182.  
  183.     OldA5 = SetCurrentA5();                        // ***** Called from trap patches *****
  184.     SetMacAppCursor(qd.arrow);
  185.     SetA5(OldA5);
  186. }
  187.  
  188. //--------------------------------------------------------------------------------------------------
  189. // if qTrace
  190. #pragma segment MABusyCursorRes
  191.  
  192. pascal CursHandle NextAnimatedCursor(AcurRsrcHandle acurRsrc)
  193. {
  194.     AcurRsrcRecord& whichAcurRsrc = **acurRsrc;    // OK: it's locked down in InitAnimatedCursor
  195.  
  196.     if (++whichAcurRsrc.whichCursor >= whichAcurRsrc.noOfCursors)
  197.         whichAcurRsrc.whichCursor = 0;
  198.  
  199.     return whichAcurRsrc.cursors[whichAcurRsrc.whichCursor].Memory.h;
  200. }
  201.  
  202. //--------------------------------------------------------------------------------------------------
  203. #pragma segment MABusyCursorRes
  204.  
  205. pascal void ABusyTask(void)
  206. {
  207.     const short theOffset = sizeof(long) * 2;
  208.     CursorInfoPointer theCursorInfoPtr = (CursorInfoPointer)(GetParmBlockPtr() - theOffset);
  209.  
  210.     // Set up application's A5 because the call to SetCursor assumes it && we need it to get pCursorInfo.
  211.     // Our A5 is prepended to the QElem which is pointed at by A0
  212.  
  213.     pCursorInfo.aQElemWithA5.OldA5 = SetA5(theCursorInfoPtr->aQElemWithA5.A5);
  214.  
  215.     // always Reset the vblCount 
  216.     pCursorInfo.aQElemWithA5.q.vblCount = pCursorInfo.busyDelay;
  217.  
  218.     if (!GetCrsrBusy() && pCursorInfo.inControl && pCursorInfo.changeToBusy)
  219.         if (pCursorInfo.cursorState)            // if we have an animated cursor 
  220.         {
  221.             if (!pCursorInfo.busyOn)
  222.                 pCursorInfo.spinCount = 0;
  223.             if (pCursorInfo.spinCount <= pCursorInfo.timeoutCount)
  224.             {
  225.                 pCursorInfo.currentCursor = **NextAnimatedCursor(pCursorInfo.cursorState);
  226.                 SetCursor(pCursorInfo.currentCursor);
  227.                 pCursorInfo.spinCount = pCursorInfo.spinCount + 1;
  228.             }
  229.             pCursorInfo.aQElemWithA5.q.vblCount = pCursorInfo.animateDelay;
  230.         }
  231.         else if (!pCursorInfo.busyOn)
  232.             SetCursor(pCursorInfo.currentCursor);
  233.  
  234.     SetA5(pCursorInfo.aQElemWithA5.OldA5);
  235. }
  236.  
  237. //--------------------------------------------------------------------------------------------------
  238. #pragma segment MAInit
  239.  
  240. pascal void TBusyCursor::IBusyCursor(void)
  241. {
  242.     UseROMMap(TRUE);
  243.     gBusyCursor = this;
  244.  
  245.     // Setup the pCursorInfo record 
  246.     pCursorInfo.inControl = TRUE;                // we are in control during initialization 
  247.     pCursorInfo.origCursor = qd.arrow;
  248.     pCursorInfo.busyDelay = kBusyDelay;
  249.     pCursorInfo.inColor = FALSE;
  250.     pCursorInfo.changeToBusy = TRUE;
  251.     pCursorInfo.busyOn = FALSE;
  252.     pCursorInfo.cursorState = this->InitAnimatedCursor(kAcurRsrcID);// init the animated cursor routine
  253.     if (pCursorInfo.cursorState)
  254.         pCursorInfo.currentCursor = **NextAnimatedCursor(pCursorInfo.cursorState);// get the first cursor
  255.     else
  256.         pCursorInfo.currentCursor = **GetCursor(watchCursor);
  257.     pCursorInfo.animateDelay = kAnimateDelay;
  258.     this->SetTimeout(kTicksBeforeTimeout);            // NOTE: needs pCursorInfo.animateDelay
  259.  
  260.     // Setup the VBL task 
  261.     pCursorInfo.aQElemWithA5.q.qType = vType;
  262.     pCursorInfo.aQElemWithA5.q.vblAddr = &ABusyTask;
  263.     pCursorInfo.aQElemWithA5.q.vblCount = kBusyDelay;
  264.     pCursorInfo.aQElemWithA5.q.vblPhase = 0;
  265.     pCursorInfo.aQElemWithA5.A5 = (long)GetA5();
  266.     // This will make the A5 world available to the VBL task 
  267.  
  268.     // Patch the necessary traps 
  269.     FailOSErr(Head1Patch(pSCPatch, _SetCursor, (Ptr) & SetMacAppCursor));// SetCursor 
  270.     FailOSErr(HeadPatch(pICPatch, _InitCursor, (Ptr) & InitMacAppCursor));// InitCursor 
  271.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  272.         FailOSErr(Head1Patch(pSCCPatch, _SetCCursor, (Ptr) & SetCMacAppCursor));// SetCCursor 
  273.  
  274.     // Install the VBL task 
  275.     FailOSErr(VInstall((QElemPtr) & pCursorInfo.aQElemWithA5.q));
  276.  
  277.     // Patch the traps applicable 
  278.     FailOSErr(HeadPatch(pGNEPatch, _GetNextEvent, (Ptr) & ResetBusyCursor));// GetNextEvent 
  279.     FailOSErr(HeadPatch(pEAPatch, _EventAvail, (Ptr) & ResetBusyCursor));// EventAvail 
  280.     if (gConfiguration.hasAUX)
  281.     {
  282.         FailOSErr(HeadPatch(pSDPatch, _StillDown, (Ptr) & ResetBusyCursor));// StillDown 
  283.         FailOSErr(HeadPatch(pWMUPatch, _WaitMouseUp, (Ptr) & ResetBusyCursor));// WaitMouseUp 
  284.     }
  285.  
  286.     // Turn on busy cursor right now; init busyDelay 
  287.     this->Delay(kBusyDelay);
  288.     this->ForceBusy();
  289. }
  290.  
  291. //--------------------------------------------------------------------------------------------------
  292. #pragma segment MATerminate
  293.  
  294. pascal void TBusyCursor::Free(void)
  295. {
  296.     this->Reset(1);                                    // Restore the non-busy cursor 
  297.     // Remove the VBL task 
  298.     VRemove((QElemPtr) & pCursorInfo.aQElemWithA5.q);
  299.  
  300.     if (pCursorInfo.cursorState)
  301.     {
  302.         for (short i = 0; i < (*pCursorInfo.cursorState)->noOfCursors; ++i)
  303.             ReleaseResource((Handle)(*pCursorInfo.cursorState)->cursors[i].Memory.h);
  304.         pCursorInfo.cursorState = (AcurRsrcHandle)DisposeIfHandle((Handle)pCursorInfo.cursorState);
  305.     }
  306.  
  307.     // Unpatch the patches 
  308.     UnpatchTrap(pICPatch);
  309.     UnpatchTrap(pSCPatch);
  310.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  311.         UnpatchTrap(pSCCPatch);
  312.  
  313.     UnpatchTrap(pGNEPatch);
  314.     UnpatchTrap(pEAPatch);
  315.     if (gConfiguration.hasAUX)
  316.     {
  317.         UnpatchTrap(pSDPatch);
  318.         UnpatchTrap(pWMUPatch);
  319.     }
  320.  
  321.     inherited::Free();
  322. }
  323. //--------------------------------------------------------------------------------------------------
  324. // if qTrace
  325. #pragma segment MABusyCursorRes
  326.  
  327. pascal void TBusyCursor::Reset(short delayTicks)
  328. {
  329.     if (pCursorInfo.inControl && pCursorInfo.changeToBusy)
  330.     {
  331.         if (pCursorInfo.busyOn)
  332.             if (pCursorInfo.inColor)
  333.                 SetCCursor(pCursorInfo.origCCursor);
  334.             else
  335.                 SetCursor(pCursorInfo.origCursor);
  336.         pCursorInfo.aQElemWithA5.q.vblCount = delayTicks;
  337.     }
  338. }
  339.  
  340. //--------------------------------------------------------------------------------------------------
  341. // if qTrace
  342. #pragma segment MABusyCursorRes
  343.  
  344. pascal void TBusyCursor::Activate(Boolean entering)
  345. {
  346.     this->Reset(pCursorInfo.busyDelay);
  347.     pCursorInfo.inControl = entering;
  348. }
  349.  
  350. //--------------------------------------------------------------------------------------------------
  351. #pragma segment MABusyCursorRes
  352.  
  353. pascal void TBusyCursor::Delay(short newDelay)
  354. {
  355.     if (newDelay > 0)                            // save new delay time 
  356.     {
  357.         pCursorInfo.busyDelay = newDelay;
  358.         this->Reset(newDelay);                        // reset timer 
  359.     }
  360. }
  361.  
  362. //--------------------------------------------------------------------------------------------------
  363. #pragma segment MABusyCursorRes
  364.  
  365. pascal void TBusyCursor::ForceBusy(void)
  366. {
  367.     // trigger on next tick and reset timer 
  368.     this->Reset(1);
  369. }
  370.  
  371. //--------------------------------------------------------------------------------------------------
  372. // if qTrace
  373. #pragma segment MABusyCursorRes
  374.  
  375. // This is called from InitMacAppCursor, SetMacAppCursor and SetCMacAppCursor.
  376. // It sets pCursorInfo fields to indicate that the cursor is not the
  377. // busy cursor.
  378. pascal void TBusyCursor::TurnOff(void)
  379. {
  380.     if (pCursorInfo.inControl && pCursorInfo.changeToBusy)
  381.     {
  382.         pCursorInfo.busyOn = FALSE;                // anyone that sets the busy cursor should set this TRUE explicitly
  383.         pCursorInfo.aQElemWithA5.q.vblCount = pCursorInfo.busyDelay;
  384.     }
  385. }
  386.  
  387. //--------------------------------------------------------------------------------------------------
  388. #pragma segment MAInit
  389.  
  390. pascal AcurRsrcHandle TBusyCursor::InitAnimatedCursor(short acurRsrcId)
  391. {
  392.     AcurRsrcHandle acurRsrc;
  393.  
  394.     acurRsrc = (AcurRsrcHandle)GetResource('acur', acurRsrcId);
  395.  
  396.     if (acurRsrc)
  397.     {
  398.         DetachResource((Handle)acurRsrc);        // So Resource Mgr doesn't unlock it for us 
  399.         MoveHHi((Handle)acurRsrc);
  400.         HLock((Handle)acurRsrc);
  401.         (*acurRsrc)->whichCursor = 0;
  402.  
  403.         // Load each cursor in the sequence and lock them in memory 
  404.         for (short i = 0; i < (*acurRsrc)->noOfCursors; ++i)
  405.         {
  406.             CursHandle theCursor = GetCursor((*acurRsrc)->cursors[i].Disk.rsrcId);// Get the cursor from the disk
  407.             FailNILResource((Handle)theCursor);
  408.             (*acurRsrc)->cursors[i].Memory.h = theCursor;    // remember the cursor
  409.             DetachResource((Handle)theCursor);    // So Resource Mgr doesn't unlock it for us 
  410.             MoveHHi((Handle)theCursor);
  411.             HLock((Handle)theCursor);            // Make sure it is locked
  412.         }
  413.     }
  414.     return acurRsrc;
  415. }
  416.  
  417. //-------------------------------------------------------------------------------------
  418. #pragma segment MABusyCursorRes
  419.  
  420. pascal void TBusyCursor::Animate(void)
  421. {
  422.     pCursorInfo.spinCount = 0;                    // zero spins since we last heard from the app
  423. }
  424.  
  425. //-------------------------------------------------------------------------------------
  426. #pragma segment MABusyCursorRes
  427.  
  428. pascal void TBusyCursor::SetTimeout(long ticksBeforeTimeout)
  429. {
  430.     pCursorInfo.timeoutCount = ticksBeforeTimeout / pCursorInfo.animateDelay;
  431.     pCursorInfo.spinCount = 0;
  432. }
  433.  
  434.  
  435.